#include "Application.h"

#include <QFuture>
#include <QFutureWatcher>
#include <QtConcurrent>

#include <iostream>

#include "LeGerber/job.h"

using namespace LeGerber;

Application::Application(int &argc, char **argv):
    QApplication(argc, argv),
    m_watcher(new QFutureWatcher<Job*>(this))
{
	connect(m_watcher, &QFutureWatcher<Job*>::finished,
	        this, &Application::onFinished);
	connect(m_watcher, &QFutureWatcher<Job*>::progressValueChanged,
	        this, &Application::onProgressValueChanged);
	connect(m_watcher, &QFutureWatcher<Job*>::resultsReadyAt,
	        this, &Application::onResultsReadyAt);
}

int Application::runJobsConcurently(const QList<Job *> jobs)
{
	m_jobs = jobs;
	m_future = QtConcurrent::mapped(m_jobs, Application::runJob);
	m_watcher->setFuture(m_future);
	return exec();
}

int Application::runJobsSequentially(const QList<Job *> jobs)
{
	m_jobs = jobs;
	for (int i =0; i<m_jobs.count(); i++)
	{
		m_jobs.at(i)->run();
		onResultReadyAt(i);
	}
	return 0;
}

void Application::onProgressValueChanged()
{
	int value = m_watcher->progressValue() - m_watcher->progressMinimum();
	int range = m_watcher->progressMaximum() - m_watcher->progressMinimum();
	qreal pc = 100.0 * qreal(value) / qreal(range);
	report(QString("%1%, %2/%3, %4 errors, %5 warnings")
	       .arg(pc, 5, 'f', 2)
	       .arg(value)
	       .arg(range)
	       .arg(errorCount)
	       .arg(warningCount));
}

void Application::onFinished()
{
	quit();
}

void Application::onResultReadyAt(int index)
{
	Job *job = m_jobs.at(index);

	for (auto message: job->warningMessages())
		warning(QString("%1: Warning: %2").arg(job->inputFilePath()).arg(message));

	if (job->isError())
		error(QString("%1: Error: %2").arg(job->inputFilePath()).arg(job->errorMessage()));

	delete job;
}

void Application::onResultsReadyAt(int beginIndex, int endIndex)
{
	for (int i = beginIndex; i < endIndex; i++)
		onResultReadyAt(i);
}

void Application::warning(const QString &text)
{
	std::cerr << text.toStdString() << std::endl;
	warningCount++;
}

void Application::error(const QString &text)
{
	std::cerr << text.toStdString() << std::endl;
	errorCount++;
}

void Application::report(const QString &text)
{
	std::cout << text.toStdString() << std::endl;
}

Job *Application::runJob(Job *job)
{
	job->run();
	return job;
}
